﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System;
using PersonaLibrary.Data;

namespace PersonaLibrary.PrintReports
{
	internal class Column : ReportItemParent
	{
		private bool _isVisible;

		public Column(string header)
		{
			Header = header;
			_isVisible = true;
		}

		public string Header { get; private set; }

		public bool IsVisible
		{
			set { _isVisible = value; RisePropertyChanged("IsVisible"); }
			get { return _isVisible; }
		}

		public Border CellBorder
		{
			get
			{
				return new Border
				       	{
				       		BorderThickness = new Thickness(0.2),
							BorderBrush = Brushes.Black,
							Padding = new Thickness(1)
				       	};
			}
		}

		public override string ToString()
		{
			return Header;
		}
	}

	internal class ReportItemParent : INotifyPropertyChanged
	{
		private double _size;
		private FontFamily _font;
		private FontWeight _bold;
		private GridLength _width;
		private Func<Employee, object> _valueSelector;

		public Func<Employee, object> ValueSelector
		{
			set { _valueSelector = value; RisePropertyChanged("ValueSelector"); }
			get { return _valueSelector; }
		}

		public GridLength Width
		{
			set { _width = value; RisePropertyChanged("Width"); }
			get { return _width; }
		}

		public double Size
		{
			set { _size = value; RisePropertyChanged("Size"); }
			get { return _size; }
		}

		public FontFamily Font
		{
			set { _font = value; RisePropertyChanged("Font"); }
			get { return _font; }
		}

		public FontWeight Bold
		{
			set { _bold = value; RisePropertyChanged("Bold"); }
			get { return _bold; }
		}

		public ICollection<FontFamily> Fonts
		{
			get { return System.Windows.Media.Fonts.SystemFontFamilies; }
		}

		public event PropertyChangedEventHandler PropertyChanged = delegate { };

		protected void RisePropertyChanged(string name)
		{
			PropertyChanged(this, new PropertyChangedEventArgs(name));
		}
	}

	internal class ReportItemText : ReportItem
	{
		private string _text;
		private readonly ReportItemParent _parent;
		private Employee _employee;
		private TextBlock _control;

		public ReportItemText(ReportItemParent parent)
		{
			_parent = parent;
			_control = new TextBlock();
		}

		public string Text
		{
			set { _text = value; RisePropertyChanged("Text"); }
			get { return _text; }
		}

		public override FrameworkElement ToControl(Employee arg)
		{
			if (_employee != null)
				_employee.PropertyChanged -= arg_PropertyChanged;

			_employee = arg;
			
			if (_employee != null)
				_employee.PropertyChanged += arg_PropertyChanged;

			Binding sizeBind = new Binding("Size") { Source = _parent, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
			_control.SetBinding(TextBlock.FontSizeProperty, sizeBind);

			Binding fontBind = new Binding("Font") { Source = _parent, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
			_control.SetBinding(TextBlock.FontFamilyProperty, fontBind);

			Binding boldBind = new Binding("Bold") { Source = _parent };
			_control.SetBinding(TextBlock.FontWeightProperty, boldBind);

			if (_parent.ValueSelector != null && string.IsNullOrEmpty(Text))
				_control.Text = Convert.ToString(_parent.ValueSelector.Invoke(arg));
			else
				_control.Text = Text;

			_control.TextWrapping = TextWrapping.Wrap;

			_control.Unloaded += result_Unloaded;

			return _control;
		}

		void arg_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (_parent.ValueSelector != null && string.IsNullOrEmpty(Text))
				_control.Text = Convert.ToString(_parent.ValueSelector.Invoke(_employee));
		}

		void result_Unloaded(object sender, RoutedEventArgs e)
		{
			if(_employee != null)
				_employee.PropertyChanged -= arg_PropertyChanged;
		}
	}

	internal abstract class ReportItem : INotifyPropertyChanged
	{
		public abstract FrameworkElement ToControl(Employee arg);

		public event PropertyChangedEventHandler PropertyChanged = delegate { };

		protected void RisePropertyChanged(string name)
		{
			PropertyChanged(this, new PropertyChangedEventArgs(name));
		}
	}
}
